﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using CmdTailCmd;
using regxExtensions;

namespace regx
{
    public class SearchFileParams : RegxParams, ICmdTailCommand
    { //=======================================================================
        public bool IsValid(CmdTailContext ctx)
        { //-------------------------------------------------------------------
            return (File.IsNotEmpty() && Pattern != null);
        }
        
        public bool Execute(object o) 
        { //-------------------------------------------------------------------
            ErrorLevel      el  = o as ErrorLevel;
            
            IEnumerable<FileInfo> files = GetFilesFromSpec();
            if (!InitializeExecution(files.Count() == 1 ? Sources.Single : Sources.Multiple)) return false;
            
            if (Debug)              
            {
                // Show regex info
                _searcher.DebugOut();
                
                // Show output format info
                RegexResultFormatter rrf = MakeFormatter(files.Count() > 0 ? GetDisplayPath(files.First()) : null);
                rrf.DebugOut();

                // Show search list
                if (Recurse) {Console.WriteLine(@"Searching recursively");}
                switch (files.Count())
                {
                    case 0:
                    {
                        Console.WriteLine(@"File spec seems to match no files");
                        break;
                    }

                    case 1:
                    {
                        Console.WriteLine(@"Searching file: " + files.First());
                        break;
                    }

                    default:
                    {
                        Console.WriteLine("Searching multiple files:");
                        foreach (FileInfo fi in files) Console.WriteLine("    " + fi.FullName); 
                        break;
                    }
                }

                el.Set(ErrorLevelValue.NoError);
                return true;
            }

            if (files.Count() == 0) {DisplayError("Cannot find file: " + File); return false;}

            ErrorLevelValue elv = ErrorLevelValue.NoMatch;
            el.Set(ErrorLevelValue.NoMatch);

            foreach (FileInfo fi in files) 
            {
                elv = SearchFile(fi);
                if (ErrorLevelValue.Matched == elv) el.Set(ErrorLevelValue.Matched);
            }
            return true;
        }

        private IEnumerable<FileInfo> GetFilesFromSpec()
        { //-------------------------------------------------------------------
            string FilePart     = Path.GetFileName(File);
            string DirPart      = Path.GetDirectoryName(File);
            string RelativeDir  = Path.Combine(Environment.CurrentDirectory, DirPart);

            DirectoryInfo di = new DirectoryInfo(RelativeDir);
            return di.GetFiles(FilePart, Recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We can't test if this function *could* work, we can just let it throw and do something else if it does, so we catch anything from it.")]
        private string GetDisplayPath(FileInfo fi)
        {   //-------------------------------------------------------------------
            string filename = fi.FullName;
            string basedir  = Environment.CurrentDirectory;
            try {basedir = Path.GetFullPath(Path.GetDirectoryName(File));} catch {} // This fails if File is some non-file-ish form like "*.*", but that's ok
            if (ShowRelativeNames && filename.StartsWith(basedir))
            {
                filename = filename.Substring(basedir.Length + 1);
            }
            return filename;
        }

        private ErrorLevelValue SearchFile(FileInfo fi)
        {   //-------------------------------------------------------------------
            ErrorLevelValue el = ErrorLevelValue.NoMatch;
            string filename = GetDisplayPath(fi);

            using (Stream stm = fi.OpenRead())
            {
                RegexResultFormatter rrf = MakeFormatter(filename);
                foreach (LineMatches lm in _searcher.MatchResults(stm))
                {
                    if (lm.Matches.Count > 0) el = ErrorLevelValue.Matched;
                    foreach (string Line in rrf.FormatLineMatches(lm)) Console.WriteLine(Line);
                    
                }                
            } // using (Stream stm)

            return el;
        } // SearchFile(FileInfo fi)
    }
}